<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>俄罗斯方块游戏</title>
    <style>
        body {
            background-color: #222;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            position: relative;
            font-family: Arial, sans-serif;
        }
        .game-container {
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        canvas {
            border: 1px solid #000;
            background-color: #000;
        }
        .info-panel {
            color: #fff;
            font-size: 1em;
            text-align: center;
            margin-bottom: 10px;
            padding: 10px;
            background-color: rgba(0, 0, 0, 0.7);
            border-radius: 5px;
            width: 200px;
        }
        .instructions {
            position: absolute;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            color: #fff;
            font-size: 1.2em;
        }
        .overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        .overlay-content {
            background-color: #fff;
            padding: 20px;
            border-radius: 10px;
            text-align: center;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
        }
        .overlay button {
            margin-top: 10px;
            padding: 10px 20px;
            font-size: 1em;
            cursor: pointer;
            border: none;
            border-radius: 5px;
            background-color: #0DC2FF;
            color: #fff;
        }
        .overlay button:hover {
            background-color: #0B9DD9;
        }
    </style>
</head>
<body>
    <div class="instructions">使用方向键移动和旋转方块。按空格键立即下落。</div>
    <div id="app" class="game-container">
        <div class="info-panel">
            分数: <span id="score">0</span><br>
            下一个方块:<br>
            <canvas id="next-block-canvas" width="60" height="60"></canvas><br>
            状态: <span id="status">游戏中</span>
        </div>
        <canvas id="tetris-canvas" width="400" height="533"></canvas>
        <div id="overlay" class="overlay" style="display: none;">
            <div class="overlay-content">
                <h2>游戏结束</h2>
                <p>您的最终分数: <span id="final-score">0</span></p>
                <button onclick="restartGame()">重新开始游戏</button>
            </div>
        </div>
    </div>

    <script>
        const scale = 26.67; // 缩小比例
        const arenaWidth = 15;
        const arenaHeight = 20;

        const colors = [
            null,
            '#FF0D72',
            '#0DC2FF',
            '#0DFF72',
            '#F538FF',
            '#FF8E0D',
            '#FFE138',
            '#3877FF'
        ];

        function createMatrix(w, h) {
            const matrix = [];
            while (h--) {
                matrix.push(new Array(w).fill(0));
            }
            return matrix;
        }

        function drawMatrix(matrix, offset, context) {
            matrix.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        context.fillStyle = colors[value];
                        context.strokeStyle = 'black';
                        context.lineWidth = 0.5;
                        context.fillRect((x + offset.x) * scale, (y + offset.y) * scale, scale, scale);
                        context.strokeRect((x + offset.x) * scale, (y + offset.y) * scale, scale, scale);
                    }
                });
            });
        }

        function merge(arena, player) {
            player.matrix.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        arena[y + player.pos.y][x + player.pos.x] = value;
                    }
                });
            });
        }

        function collide(arena, player) {
            const [m, o] = [player.matrix, player.pos];
            for (let y = 0; y < m.length; ++y) {
                for (let x = 0; x < m[y].length; ++x) {
                    if (m[y][x] !== 0 &&
                       (arena[y + o.y] &&
                        arena[y + o.y][x + o.x]) !== 0) {
                        return true;
                    }
                }
            }
            return false;
        }

        function createPiece(type) {
            switch (type) {
                case 'T':
                    return [
                        [0, 1, 0],
                        [1, 1, 1],
                        [0, 0, 0]
                    ];
                case 'O':
                    return [
                        [2, 2],
                        [2, 2]
                    ];
                case 'L':
                    return [
                        [0, 0, 3],
                        [3, 3, 3],
                        [0, 0, 0]
                    ];
                case 'J':
                    return [
                        [4, 0, 0],
                        [4, 4, 4],
                        [0, 0, 0]
                    ];
                case 'I':
                    return [
                        [0, 5, 0, 0],
                        [0, 5, 0, 0],
                        [0, 5, 0, 0],
                        [0, 5, 0, 0]
                    ];
                case 'S':
                    return [
                        [0, 6, 6],
                        [6, 6, 0],
                        [0, 0, 0]
                    ];
                case 'Z':
                    return [
                        [7, 7, 0],
                        [0, 7, 7],
                        [0, 0, 0]
                    ];
                default:
                    throw new Error("未知的方块类型");
            }
        }

        function rotate(matrix, dir) {
            for (let y = 0; y < matrix.length; ++y) {
                for (let x = 0; x < y; ++x) {
                    [
                        matrix[x][y],
                        matrix[y][x],
                    ] = [
                        matrix[y][x],
                        matrix[x][y],
                    ];
                }
            }

            if (dir > 0) {
                matrix.forEach(row => row.reverse());
            } else {
                matrix.reverse();
            }
        }

        const canvas = document.getElementById('tetris-canvas');
        const context = canvas.getContext('2d');

        const nextBlockCanvas = document.getElementById('next-block-canvas');
        const nextBlockContext = nextBlockCanvas.getContext('2d');

        let arena = createMatrix(arenaWidth, arenaHeight);

        let player = {
            pos: { x: 0, y: 0 },
            matrix: null,
        };

        let score = 0;
        let dropCounter = 0;
        let dropInterval = 1000;
        let lastTime = 0;
        let isGameOver = false;

        function update(time = 0) {
            if (isGameOver) return;

            const deltaTime = time - lastTime;
            lastTime = time;

            dropCounter += deltaTime;
            if (dropCounter > dropInterval) {
                playerDrop();
            }

            draw();
            requestAnimationFrame(update);
        }

        function playerDrop() {
            player.pos.y++;
            if (collide(arena, player)) {
                player.pos.y--;
                merge(arena, player);
                playerReset();
                arenaSweep();
                updateScore();
            }
            dropCounter = 0;
        }

        function playerMove(dir) {
            player.pos.x += dir;
            if (collide(arena, player)) {
                player.pos.x -= dir;
            }
        }

        function playerRotate(dir) {
            const pos = player.pos.x;
            let offset = 1;
            rotate(player.matrix, dir);
            while (collide(arena, player)) {
                player.pos.x += offset;
                offset = -(offset + (offset > 0 ? 1 : -1));
                if (offset > player.matrix[0].length) {
                    rotate(player.matrix, -dir);
                    player.pos.x = pos;
                    return;
                }
            }
        }

        function playerReset() {
            const pieces = 'ILJOTSZ';
            player.matrix = createPiece(pieces[pieces.length * Math.random() | 0]);
            player.pos.y = 0;
            player.pos.x = (arena[0].length / 2 | 0) - (player.matrix[0].length / 2 | 0);
            if (collide(arena, player)) {
                gameOver();
            }
            drawNextBlock(player.matrix);
        }

        function arenaSweep() {
            let rowCount = 1;
            outer: for (let y = arena.length - 1; y > 0; --y) {
                for (let x = 0; x < arena[y].length; ++x) {
                    if (arena[y][x] === 0) {
                        continue outer;
                    }
                }
                const row = arena.splice(y, 1)[0].fill(0);
                arena.unshift(row);
                ++y;

                score += rowCount * 10;
                rowCount *= 2;
            }
        }

        function updateScore() {
            document.getElementById('score').innerText = score;
            document.getElementById('final-score').innerText = score;
        }

        function draw() {
            context.fillStyle = '#000';
            context.fillRect(0, 0, canvas.width, canvas.height);

            drawMatrix(arena, { x: 0, y: 0 }, context);
            drawMatrix(player.matrix, player.pos, context);
        }

        function drawNextBlock(matrix) {
            nextBlockContext.clearRect(0, 0, nextBlockCanvas.width, nextBlockCanvas.height);
            nextBlockContext.fillStyle = '#000';
            nextBlockContext.fillRect(0, 0, nextBlockCanvas.width, nextBlockCanvas.height);

            drawMatrix(matrix, { x: 0, y: 0 }, nextBlockContext);
        }

        function handleKeyDown(event) {
            if (isGameOver) return;

            if (event.keyCode === 37 || event.key === 'ArrowLeft') { // 左箭头键
                playerMove(-1);
            } else if (event.keyCode === 39 || event.key === 'ArrowRight') { // 右箭头键
                playerMove(1);
            } else if (event.keyCode === 40 || event.key === 'ArrowDown') { // 下箭头键
                playerDrop();
            } else if (event.keyCode === 38 || event.key === 'ArrowUp') { // 上箭头键
                playerRotate(1);  // 顺时针旋转
            } else if (event.keyCode === 32 || event.key === ' ') { // 空格键
                while (!collide(arena, player)) {
                    player.pos.y++;
                }
                player.pos.y--;
                merge(arena, player);
                playerReset();
                arenaSweep();
                updateScore();
            }
        }

        function gameOver() {
            isGameOver = true;
            document.getElementById('status').innerText = '游戏结束';
            document.getElementById('overlay').style.display = 'block';
        }

        function restartGame() {
            arena = createMatrix(arenaWidth, arenaHeight);
            player = {
                pos: { x: 0, y: 0 },
                matrix: null,
            };
            score = 0;
            dropCounter = 0;
            dropInterval = 1000;
            lastTime = 0;
            isGameOver = false;
            document.getElementById('status').innerText = '游戏中';
            document.getElementById('overlay').style.display = 'none';
            playerReset();
            updateScore();
            update();
        }

        window.addEventListener('keydown', handleKeyDown);

        playerReset();
        updateScore();
        update();
    </script>
</body>
</html>



